using System;
using System.Collections.Generic;
using System.Diagnostics;
using PortfolioAllocator.Optimization;

namespace PortfolioAllocator.Tests
{
    using NUnit.Framework;

    [TestFixture]
    class TestMultiValues
    {
        [Test]
        [Category("Calculation")]
        public void findIntersection()
        {
            SortedList<DateTime, double> timeSeries1 = new SortedList<DateTime, double>(5);
            SortedList<DateTime, double> timeSeries2 = new SortedList<DateTime, double>(6);
            DateTime d = new DateTime(2010, 1, 1);
            timeSeries2.Add(d.AddDays(-1), -1);
            for (int i = 0; i < 5; ++i)
            {
                timeSeries1.Add(d.AddDays(i), i + 0.1);                 // ts1:     0,1,2,3,4
                timeSeries2.Add(d.AddDays(i * 2), i * 2 + 100);         // ts2: -1, 0,2,4,6,8,
            }

            List<SortedList<DateTime, double>> tsList = new List<SortedList<DateTime, double>>(2);
            tsList.Add(timeSeries1);
            tsList.Add(timeSeries2);

            DateMultiValues dValues = MultiValueUtilities.findIntersection(tsList);

            Assert.AreEqual(3, dValues.Dates.Count, "size of intersected dates");
            Assert.AreEqual(2, dValues.Values.GetLength(1), "Values: number of columns");
            Assert.AreEqual(3, dValues.Values.GetLength(0), "Values: number of rows");
            Assert.AreEqual(3, dValues.NOfRows, "Values.NOfRows");

            DateTime[] expIntersectionDates = { new DateTime(2010, 1, 1), new DateTime(2010, 1, 3), new DateTime(2010, 1, 5) };

            double[,] expValues = { { 0.1, 100 },
                                    { 2.1, 102 },
                                    { 4.1, 104 } };

            Assert.AreEqual(expIntersectionDates, dValues.Dates, "Intersection dates");
            Assert.AreEqual(expValues, dValues.Values, "Intersection values");

            string expToString = "2010-01-01:	0.1	100\r\n" + "2010-01-03:	2.1	102\r\n" + "2010-01-05:	4.1	104\r\n";
            Assert.AreEqual(expToString, dValues.ToString(), "Intersection.ToString");
        }

        [Test]
        [Category("Calculation")]
        public void calcLogReturns()
        {
            double[,] values = { {1, 1  },
                                 {2, 0.5},
                                 {4, 0.2}   };
            List<DateTime> dates = new List<DateTime>(new DateTime[] { new DateTime(2010, 1, 1), new DateTime(2010, 1, 2), new DateTime(2010, 1, 3) });

            DateMultiValues datedPrices = new DateMultiValues(dates, values);
            DateMultiValues datedLogRets = MultiValueUtilities.calcLogReturns(datedPrices);
            double[,] expVals = {   {0,0},
                                    {Math.Log(2), Math.Log(0.5)},
                                    {Math.Log(2), Math.Log(0.2/0.5)} };

            Assert.AreEqual(expVals, datedLogRets.Values, "logRets.Values");
        }

        [Test]
        [Category("Calculation")]
        public void calcExpWeightedCovMatrix()
        {
            double[,] logRets = {   {0,0},
                                    {0.0503158045598899,0.015891985159673},
                                    {-0.0457574905606751,0.00850189220929483},
                                    {0.0323973359151976,0.0680843909727442},
                                    {-0.00245667270408774,0.00711063530099676},
                                    {0.030312624044736,0.0106624747457922},
                                    {-0.0291140474751074,0.0446892694922231},
                                    {-0.0168922511599199,0.0110785867696426},
                                    {0.0120142660864473,-0.00389556276844141},
                                    {0.0362835192683103,0.0226038953287606},
                                    {-0.0553628608985284,-0.00391612577299781},
                                    {-0.00718191307704773,0.00714519806572242}};
            int n = logRets.GetLength(0);
            int m = logRets.GetLength(1);
            int nExp = 8;
            double[,] covStart = { { 0, 0 }, { 0, 0 } };
            int startIx = 0;
            int endIx = n;

            double[,] covEnd = MultiValueUtilities.calcExpCovarAB(logRets, covStart, startIx, endIx, nExp);
            double[,] covExp = { { 0.000980821141811384, 0.000120181353128857 }, { 0.000120181353128857, 0.000372268097818154 } };

            Assert.That(covExp, Is.EqualTo(covEnd).Within(1e-10), "Covariance matrix");
        }
    }
}
